package com.mall.order.mq;

import com.mall.order.dal.persistence.OrderItemMapper;
import com.mall.order.dal.persistence.OrderMapper;
import com.mall.order.dal.persistence.StockMapper;
import com.mall.order.dto.CancelOrderRequest;
import com.mall.order.services.OrderEndServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.util.List;

/**
 * @author XuBang
 * @TODO: 接收消息，验证
 * @date 2021/11/4$
 * @trainOfthought:
 */

/**
 * 开启事务：
 * 1.类：implements ApplicationContextAware，实现接口的方法；接收applicationContext
 * 2.applicationContext.getBean(DelayOrderCancelConsumer.class)  ---   获取代理对象bean
 * 3.对开启事务的方法，添加：@Transactional 注解
 * 4.使用bean代理对象，调用开启事务的方法
 */
@Component
@Slf4j
public class DelayOrderCancelConsumer implements ApplicationContextAware {

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    OrderItemMapper orderItemMapper;

    @Autowired
    StockMapper stockMapper;

    @Autowired
    OrderEndServiceImpl orderEndService;

    DefaultMQPushConsumer consumer;
    ApplicationContext applicationContext;


    @PostConstruct
    private void init() {
        log.info("顺序进入 init");
        //1.消费对象准备
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("bangbangtang");

        //2.消费地址准备
        consumer.setNamesrvAddr("127.0.0.1:9876");

        //3.设置监听器（核心部分：定义消费的逻辑代码，并返回消费成功||失败的状态码）
        consumer.setMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                try {
                    DelayOrderCancelConsumer bean = applicationContext.getBean(DelayOrderCancelConsumer.class);  //代理对象
                    bean.CancelOrder(msgs);   //通过代理对象，代用
                } catch (BeansException e) {
                    e.printStackTrace();
                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                }
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });

        //4.订阅主题
        try {
            consumer.subscribe("orderCancel_delay_message", "*");

        } catch (Exception e) {
            e.printStackTrace();
        }
            //5.启动
        try {
            consumer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
    }


    /**
     * 利用“延迟消息”自动取消订单；com.mall.order.mq.DelayOrderCancelProducer根据“延迟级别”，发送延迟消息；
     * com.mall.order.mq.DelayOrderCancelProducer监听到指令；开始调用本方法，执行“订单取消”&“库存回归”的功能
     * 注：
     * 1.为了防止意外造成的任务中断，所以：引入事务，通过代理对象调用该方法
     * 2.根据“延迟级别”发送延迟消息的工具类，放在pipeline的com.mall.order.biz.handler.SendMessageHandler方法中，进行调用
     * @param msgs
     */
    @Transactional   //开启事务，仅仅@Transactional，没有用；需要使用代理对象调用；该方法所在类，实现接口方法，生成的代理对象bean，调用
    public void CancelOrder(List<MessageExt> msgs) {
        log.info("开始执行 取消订单操作");
        long endTime = System.currentTimeMillis();

        //1.首先从消息中，取出orderId
        MessageExt message = msgs.get(0);
        String startTime = message.getUserProperty("startTime");   //producer发送信息的开始时间
        System.out.println(message.getMsgId()+"---"+"delayTime_Span:"+(endTime-Long.parseLong(startTime)));

        byte[] body = message.getBody();
        String orderId = null;
        try {
            orderId = new String(body, 0, body.length, "utf-8");
            log.info("orderId"+"-------"+orderId);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        //2.查询orderId对应的订单状态，如果订单的状态是已经支付或者取消（什么都不做）
        //3.如果订单的状态，还是一个初始化状态com.mall.order.constants.OrderConstants  ，意味着：用户还没有支付，所以：取消订单

//        //a.制定修改状态规则：根据orderId & status 对订单进行筛选
//        Example example = new Example(Order.class);
//        Example.Criteria criteria = example.createCriteria();
//        criteria.andEqualTo("orderId", orderId);
//        criteria.andEqualTo("status", OrderConstants.ORDER_STATUS_INIT);
//        //b.制定修改对象
//        Order order = new Order();
//        order.setStatus(OrderConstants.ORDER_STATUS_TRANSACTION_CANCEL);  //取消订单-交易关闭状态
//        //c.修改
//        orderMapper.updateByExampleSelective(order, example);
//
//        //4.还原可售卖库存：遍历被取消的订单中的订单商品条目，-lock_count,+stock_count
//        List<Order> orders = orderMapper.selectByExample(example);
//        Example example1 = new Example(OrderItem.class);
//        Example.Criteria criteria1 = example1.createCriteria();
//        for (Order order1 : orders) {
//            //获取被取消订单中，订单的id----》tb_order_item中，获取对应的商品数量和商品id
//            criteria1.andEqualTo(order1.getOrderId());
//            List<OrderItem> orderItems = orderItemMapper.selectByExample(example1);
//            log.info("延迟消息-消费者 开始修改库存。。。");
//            for (OrderItem orderItem : orderItems) {
//                //遍历订单id对应的所有的 商品id 和 商品数量
//                //tb_stock中，-lock_count,+stock_count
//                Stock stock = new Stock();
//                stock.setItemId(orderItem.getItemId());
//                stock.setLockCount(-orderItem.getNum());
//                stock.setStockCount(orderItem.getNum().longValue());
//                stockMapper.updateStock(stock);
//            }
//        }

        //直接调用取消订单

        //超时，执行订单取消功能
        log.info("准备进入订单取消操作");
        CancelOrderRequest cancelOrderRequest = new CancelOrderRequest();
        cancelOrderRequest.setOrderId(orderId);
        orderEndService.cancelOrder(cancelOrderRequest);

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
